package android.slc.box.core.widget.combox;

import android.slc.box.core.property.DataChangeListener
import cn.hutool.core.collection.CollUtil
import cn.hutool.core.util.StrUtil
import javafx.application.Platform
import javafx.event.EventHandler
import javafx.scene.control.ComboBox
import javafx.scene.input.MouseEvent

/**
 * 搜索选择框
 */
class SearchComBoxWrapper<T>(private val comboBox: ComboBox<T>, private val searchConversion: ((T) -> String)? = null) {
    companion object {
        //密集事件缓冲时间
        const val DEF_DENSE_POPUP_HIDE_BUFFER_TIME = 256
        const val DEF_DENSE_SELECT_ITEM_BUFFER_TIME = 256
    }

    /**
     * 默认的编辑状态
     */
    private val defComboBoxEditable = comboBox.isEditable

    /**
     * 自动清除搜索内容
     */
    var autoClearSearchText = true

    /**
     * 筛选应用在显示的时候
     */
    var filterItemsInShow = false

    /**
     * item
     */
    var items: List<T> = mutableListOf()

    /**
     * 最后一次隐藏的时间
     */
    private var lastHideTime: Long = 0

    /**
     * 最后一次选择时间
     */
    private var lastSelectTime: Long = 0

    /**
     * 密集弹框事件缓冲时间
     */
    var densePopupHideBufferTime = DEF_DENSE_POPUP_HIDE_BUFFER_TIME

    /**
     * 密集选择事件缓冲事件
     */
    var denseSelectItemBufferTime = DEF_DENSE_SELECT_ITEM_BUFFER_TIME

    /**
     * 文本变化监听
     */
    private var textPropertyDataChangeListener = DataChangeListener<String> {
        Platform.runLater {
            //此处将筛选运行在事件之后，不然系统会报错
            //Log.get().info("有变化事件")
            if (System.currentTimeMillis() - this.lastSelectTime > this.denseSelectItemBufferTime) {
                //Log.get().info("有变化事件且符合时间")
                //如果正在显示则筛选
                if (this.comboBox.isShowing) {
                    //Log.get().info("有变化事件且符合时间且是显示的")
                    val filterItems = filterItems()
                    this.comboBox.items.setAll(filterItems)
                }
            }
        }
    }

    /**
     * 鼠标事件监听
     */
    private var editorMouseClickedEvent = EventHandler<MouseEvent> {
        if (this.comboBox.isShowing) {
            this.comboBox.hide()
        } else if (System.currentTimeMillis() - this.lastHideTime > this.densePopupHideBufferTime) {
            //此处是为了防止在显示后点击输入框，popup自动消失后此处才监听到事件，此时已经识别为隐藏状态，又把输入框调用出来，防止此bug
            this.comboBox.show()
        }
    }

    /**
     * 选项框焦点变化
     */
    private var focusedPropertyDataChangeListener = DataChangeListener<Boolean> {
        if (!it && !comboBox.isShowing) {
            applyValue2EditText()
        }
    }

    /**
     * 值属性变化
     */
    private var valuePropertyDataChangeListener = DataChangeListener<T> { itValue ->
        this.lastSelectTime = System.currentTimeMillis()
    }

    /**
     * 选择框显示监听
     */
    private var showingPropertyDataChangeListener = DataChangeListener<Boolean> {
        if (it) {
            //Log.get().info("框显示")
            this.comboBox.items.setAll(this.items)
            if (this.filterItemsInShow) {
                Platform.runLater {
                    val filterItems = filterItems()
                    this.comboBox.items.setAll(filterItems)
                }
            }
        } else {
            //Log.get().info("框消失")
            this.lastHideTime = System.currentTimeMillis()
            applyValue2EditText()
        }
    }

    /**
     * 应用搜索
     */
    fun applySearch() {
        if (!this.defComboBoxEditable) {
            //开启编辑
            this.comboBox.isEditable = true
        }
        //编辑文本监听
        this.comboBox.editor.textProperty().addListener(textPropertyDataChangeListener)
        //添加输入框点击事件监听
        this.comboBox.editor.addEventFilter(MouseEvent.MOUSE_CLICKED, editorMouseClickedEvent)
        //添加输入框点击事件监听
        this.comboBox.editor.focusedProperty().addListener(focusedPropertyDataChangeListener)
        //值变化监听
        this.comboBox.valueProperty().addListener(valuePropertyDataChangeListener)
        //添加显示状态监听
        this.comboBox.showingProperty().addListener(showingPropertyDataChangeListener)
    }

    /**
     * 放弃应用搜索
     */
    fun abandonApplySearch() {
        if (!this.defComboBoxEditable) {
            //开启编辑
            this.comboBox.isEditable = false
        }
        //编辑文本监听
        this.comboBox.editor.textProperty().removeListener(textPropertyDataChangeListener)
        //添加输入框点击事件监听
        this.comboBox.editor.removeEventFilter(MouseEvent.MOUSE_CLICKED, editorMouseClickedEvent)
        //添加输入框点击事件监听
        this.comboBox.editor.focusedProperty().removeListener(focusedPropertyDataChangeListener)
        //值变化监听
        this.comboBox.valueProperty().removeListener(valuePropertyDataChangeListener)
        //添加显示状态监听
        this.comboBox.showingProperty().removeListener(showingPropertyDataChangeListener)
    }

    /**
     * 应用值附加到输入框上
     */
    private fun applyValue2EditText() {
        //Log.get().info("应用选项值到输入框——尝试")
        if (this.autoClearSearchText) {
            //Log.get().info("应用选项值到输入框")
            this.lastSelectTime = System.currentTimeMillis()
            this.comboBox.value?.let { itValue ->
                //Log.get().info("应用选项值到输入框已渲染")
                val valueText = searchConversion?.invoke(itValue) ?: itValue.toString()
                this.comboBox.editor.text = valueText
            } ?: let {
                //Log.get().info("应用选项值到输入框滞空")
                this.comboBox.editor.text = ""
            }
        }
    }

    /**
     * 过滤item
     */
    private fun filterItems(): Collection<T> {
        return CollUtil.filterNew(this.items) { itItem ->
            return@filterNew searchConversion?.let { itSearchConversion ->
                StrUtil.contains(itSearchConversion.invoke(itItem), this.comboBox.editor.text)
            } ?: StrUtil.contains(itItem.toString(), this.comboBox.editor.text)
        }
    }
}